﻿// <copyright file="ProjectionCamera.cs" company="Axelerate Solutions S.A.">
// Copyright (c) Axelerate Solutions S.A.  All rights reserved.
// </copyright>

namespace Axelerate.Silverlight3D.Media.Media3D
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    /// <summary>
    /// File name: ProjectionCamera.cs
    /// Company: Axelerate Solutions S.A.
    /// Created By: Daniel Rojas
    /// Created Date: 10/10/2008 16:02:00 h.
    /// Description: Gets or sets a Vector3D which defines the upward direction of the camera. This is a dependency property.
    ///   <Modifications>
    ///   </Modifications>
    /// </summary>
    public abstract class ProjectionCamera : Camera
    {
        #region Fields
        /// <summary>
        /// Identifies the FarPlaneDistance dependency property.
        /// </summary>
        public static readonly DependencyProperty FarPlaneDistanceProperty =
                    DependencyProperty.Register(
                          "ProjectionCamera",
                          typeof(double),
                          typeof(ProjectionCamera),
                          new PropertyMetadata(OnFarPlaneDistancePropertyChanged));

        /// <summary>
        /// Identifies the LookDirection dependency property..
        /// </summary>
        public static readonly DependencyProperty LookDirectionProperty =
                    DependencyProperty.Register(
                          "LookDirection",
                          typeof(Vector3D),
                          typeof(ProjectionCamera),
                          new PropertyMetadata(OnLookDirectionPropertyChanged));

        /// <summary>
        /// Identifies the NearPlaneDistance dependency property..
        /// </summary>
        public static readonly DependencyProperty NearPlaneDistanceProperty =
                    DependencyProperty.Register(
                          "NearPlaneDistance",
                          typeof(double),
                          typeof(ProjectionCamera),
                          new PropertyMetadata(OnNearPlaneDistancePropertyChanged));

        /// <summary>
        /// Identifies the Position dependency property..
        /// </summary>
        public static readonly DependencyProperty PositionProperty =
                    DependencyProperty.Register(
                          "Position",
                          typeof(Point3D),
                          typeof(ProjectionCamera),
                          new PropertyMetadata(OnPositionPropertyChanged));

        /// <summary>
        /// public static readonly DependencyProperty UpDirectionProperty
        /// </summary>
        public static readonly DependencyProperty UpDirectionProperty =
                    DependencyProperty.Register(
                          "UpDirection",
                          typeof(Vector3D),
                          typeof(ProjectionCamera),
                          new PropertyMetadata(OnUpDirectionPropertyChanged));

        #endregion

        #region Properties
        
        /// <summary>
        /// Gets or sets a value that specifies the distance from the camera of the camera's far clip plane. This is a dependency property.
        /// </summary>
        public double FarPlaneDistance
        {
            get
            {
                return (double)this.GetValue(FarPlaneDistanceProperty);
            }
            set
            {
                this.SetValue(FarPlaneDistanceProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a Vector3D which defines the direction in which the camera is looking in world coordinates. This is a dependency property.
        /// </summary>
        public Vector3D LookDirection
        {
            get
            {
                return (Vector3D)this.GetValue(LookDirectionProperty);
            }
            set
            {
                this.SetValue(LookDirectionProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a value that specifies the distance from the camera of the camera's near clip plane. This is a dependency property.
        /// </summary>
        public double NearPlaneDistance
        {
            get
            {
                return (double)this.GetValue(NearPlaneDistanceProperty);
            }
            set
            {
                this.SetValue(NearPlaneDistanceProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the position of the camera in world coordinates. This is a dependency property.
        /// </summary>
        public Point3D Position
        {
            get
            {
                return (Point3D)this.GetValue(PositionProperty);
            }
            set
            {
                this.SetValue(PositionProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets a Vector3D which defines the upward direction of the camera. This is a dependency property.
        /// </summary>
        public Vector3D UpDirection
        {
            get
            {
                return (Vector3D)this.GetValue(UpDirectionProperty);
            }
            set
            {
                this.SetValue(UpDirectionProperty, value);
            }
        }

        #endregion

        protected ProjectionCamera() : base()
        {
            // These are the same values that WPF uses for its initial values
            // for projection based cameras
            this.FarPlaneDistance = double.PositiveInfinity;
            this.NearPlaneDistance = 0.125;
            this.LookDirection = new Vector3D(0, 0, -1);
            this.UpDirection = new Vector3D(0, 1, 0);
            this.Position = new Point3D(0, 0, 0);
        }


        #region Methods
        /// <summary>
        /// Raise the FarPlaneDistance changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnFarPlaneDistancePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ProjectionCamera)d).NotifyPropertyChanged("FarPlaneDistance");
            ((ProjectionCamera)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the LookDirection changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnLookDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ProjectionCamera)d).NotifyPropertyChanged("LookDirection");
            ((ProjectionCamera)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the NearPlaneDistance changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnNearPlaneDistancePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ProjectionCamera)d).NotifyPropertyChanged("NearPlaneDistance");
            ((ProjectionCamera)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the Position changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ProjectionCamera)d).NotifyPropertyChanged("Position");
            ((ProjectionCamera)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the UpDirection changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnUpDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ProjectionCamera)d).NotifyPropertyChanged("UpDirection");
            ((ProjectionCamera)d).IsDirty = true;
        }
        #endregion
    }
}
